# 1.默认参数
# 必选参数在前，默认参数在后
def power(x, n = 3):
    s = 1
    while n > 0:
        n = n-1
        s *= x
    return s

print(power(2))

# 多个默认参数是可以指定默认参数的值
# 规则： 无指定特殊默认参数值时，按按顺序给默认参数赋值
def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)
enroll('Bob', 'M', 7)
enroll('Adam', 'M', city='Tianjin')

# 默认参数必须指向不可变参数，所以不要将list定义为默认参数
def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

# 2.可变参数 -> 自动组装成tuple
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
calc(1,2,3,4)
calc(1,2,3,4,5)

# 如果已经有了一个list或者tuple
numbers = [1,3,5,7]
calc(*numbers)

# 3.关键字参数 -> 自动组装成dict
extra = {'city': 'shanghai', 'job': 'Engineer'}
def person(name, age, **args):
    print('name:', name, ', age:', age, ',others:', args)
person('baoman', 28, **extra)

# 4.命名关键字参数
# 定义只接收的关键字，由'*'隔开，'*'后面的表示命名关键字参数, 调用时需要键入关键字名称
def person2(name, age, *, city, job):
    print(name, age, city, job)
person2('baoman', 20 , job='code', city='shanghai')

# 如果变量中已经有一个可变参数，那么可以省略特殊符号'*'跟在后边的参数是命名参数
def person3(name, age, *args, city, job):
    print(name, age, args, city,job)
person3('wubin', 21, 88, 100, city='上海', job='coding')

# 命名参数也可以设置缺省, 此时该命名参数可以不传值
def person4(name, age, *, city='上海', job):
    print(name, age, city, job)
person4('baoman', 22, job='coding')

# 组合参数的定义顺序：
# 必选参数、默认参数、可变参数、命名关键字参数和关键字参数
# 任何函数都可以通过func(*args, **kw)的形式调用，无论他如何定义（args为tuple, kw为dict）

# 练习
# 以下函数允许计算两个数的乘积，请稍加改造，变成可接收一个或多个数并计算乘积
def product(num, *args):
    if not isinstance(num, (int, float)):
        raise TypeError('初始值类型错误')
    for n in args:
        num = num * n
    return num

# 测试
print('product(5) =', product(5))
print('product(5, 6) =', product(5, 6))
print('product(5, 6, 7) =', product(5, 6, 7))
print('product(5, 6, 7, 9) =', product(5, 6, 7, 9))
if product(5) != 5:
    print('测试失败!')
elif product(5, 6) != 30:
    print('测试失败!')
elif product(5, 6, 7) != 210:
    print('测试失败!')
elif product(5, 6, 7, 9) != 1890:
    print('测试失败!')
else:
    try:
        product()
        print('测试失败!')
    except TypeError:
        print('测试成功!')